package com.wei.czz.framework.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.enums.blog.comment.CommentEnum;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.dto.blog.comment.CommentDto;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.blog.BlogCommentVo;
import com.wei.czz.common.vo.blog.comment.CommentFormVo;
import com.wei.czz.framework.blog.dao.BlogCommentDao;
import com.wei.czz.framework.blog.entity.BlogCommentEntity;
import com.wei.czz.framework.common.service.SnowflakeService;
import com.wei.czz.framework.blog.service.BlogCommentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-08-24 22:48:40
 * className: BlogCommentServiceImpl 博客评论操作请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("blogCommentService")
@AllArgsConstructor
public class BlogCommentServiceImpl extends ServiceImpl<BlogCommentDao, BlogCommentEntity> implements BlogCommentService {

    public static final Logger log = LoggerFactory.getLogger(BlogCommentServiceImpl.class);

    private final SnowflakeService snowflakeService;

    @Transactional
    @Override
    public Long saveComment(BlogCommentVo blogCommentVo) {

        Long parentCommentId = CommonEnum.ZERO.getLongValue();
        if (Objects.nonNull(blogCommentVo.getParentCommentId())) {
            parentCommentId = blogCommentVo.getParentCommentId();

            LambdaQueryWrapper<BlogCommentEntity> blogCommentLambdaWrapper = new LambdaQueryWrapper<>();
            // 匹配 评论主键 字段
            blogCommentLambdaWrapper.eq(BlogCommentEntity::getCommentId, parentCommentId);
            // 查询数据库系统博客评论表，统计博客评论主键出现的次数
            long count = this.count(blogCommentLambdaWrapper);
            if (count == 0) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您回复的评论不存在，请确认，如有问题，请联系管理员处理。");
            }
        }

        // 获取正在评论自己博客的用户
        UserPo user = SecurityUtils.getUser();

        // 判断评论区块是否存在
        Long blockId = blogCommentVo.getBlockId();
        if (Objects.isNull(blockId)) {
            blockId = snowflakeService.get();
            log.info("博客评论区块主键为空，使用新值：{}", blockId);
        }
        // 博客作者是否点赞评论
        boolean authorLikeFlag = blogCommentVo.getAuthorLike().equals(CommentEnum.AUTHOR_LIKE.getValue());

        BlogCommentEntity comment = new BlogCommentEntity();
        // 设置博客id、区块id（雪花主键）、被评论用户id（‘默认用户id’）和评论内容属性值
        comment.setParentCommentId(parentCommentId)
                .setBlogId(blogCommentVo.getBlogId())
                .setBlockId(blockId)
                .setParentUserId(CommonEnum.ZERO.getLongValue())
                .setContent(blogCommentVo.getContent());
        if (!Objects.equals(parentCommentId, CommonEnum.ZERO.getLongValue())) {
            /*
                被回复评论主键不是默认值
             */
            // 设置被评论用户id属性值
            comment.setParentUserId(blogCommentVo.getParentUserId());
        }

        // 初始化一些评论信息
        this.initCommentField(comment, user);
        if (authorLikeFlag) {
            // 作者点赞且评论点赞数为1
            comment.setLikeNum(1)
                    .setAuthorLike(blogCommentVo.getAuthorLike());
        }
        // 设置是否置顶属性值
        comment.setTopFlag(blogCommentVo.getTopFlag());

        // 操作数据库系统博客评论表，新增一条用户评论博客信息
        int count = baseMapper.insert(comment);
        log.info("保存博客评论完成。count={}", count);

        return comment.getCommentId();
    }

    @Override
    public CommentDto saveOneComment(BlogCommentVo blogCommentVo) {

        // 获取当前正在评论博客的用户
        UserPo user = SecurityUtils.getUser();

        BlogCommentEntity comment = new BlogCommentEntity();
        // 设置博客id、区块id（雪花主键）、被评论用户id（评论博客）和评论内容属性值
        comment.setParentCommentId(CommonEnum.ZERO.getLongValue())
                .setBlogId(blogCommentVo.getBlogId())
                .setBlockId(snowflakeService.get())
                .setParentUserId(CommonEnum.ZERO.getLongValue())
                .setContent(blogCommentVo.getContent());
        // 初始化一些评论信息
        this.initCommentField(comment, user);

        // 操作数据库系统博客评论表，新增一条用户评论博客信息
        int count = baseMapper.insert(comment);
        log.info("保存一级博客评论完成。count={}", count);

        // 评论信息封装并设置对应的用户名称和用户头像
        CommentDto commentDto = new CommentDto();
        // 属性值复制
        BeanUtils.copyProperties(comment, commentDto);
        // 设置评论id、区块id、用户id、评论用户名称和评论用户头像属性值
        commentDto.setCommentId(comment.getCommentId().toString())
                .setBlockId(comment.getBlockId().toString())
                .setUserId(comment.getUserId().toString())
                .setUserName(user.getUsername())
                .setUserAvatar(user.getAvatar());
        return commentDto;
    }

    @Override
    public CommentDto saveChildComment(BlogCommentVo blogCommentVo) {
        Long blogId = blogCommentVo.getBlogId();
        // 被评论用户id类型转换
        long parentUserId = blogCommentVo.getParentUserId();

        // 用户间相互评论
        LambdaQueryWrapper<BlogCommentEntity> blogCommentLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 评论区块id和被评论用户id 字段
        blogCommentLambdaWrapper.eq(BlogCommentEntity::getBlockId, blogCommentVo.getBlockId())
                .eq(BlogCommentEntity::getUserId, parentUserId)
                .eq(BlogCommentEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据库系统博客评论表，统计符合检索条件的博客评论个数
        long count = this.count(blogCommentLambdaWrapper);
        log.info("判断回复评论是否存在完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "回复用户不存在，请确认，如有问题，请联系管理员处理。");
        }

        // 获取当前登录的用户
        UserPo user = SecurityUtils.getUser();

        BlogCommentEntity comment = new BlogCommentEntity();
        // 设置博客id、区块id、被评论用户id、评论内容属性值
        comment.setParentCommentId(blogCommentVo.getParentCommentId())
                .setBlogId(blogId)
                .setBlockId(blogCommentVo.getBlockId())
                .setParentUserId(parentUserId)
                .setContent(blogCommentVo.getContent());

        // 初始化博客评论的基本信息
        this.initCommentField(comment, user);

        log.info("保存用户互相评论信息: {}", comment);
        count = baseMapper.insert(comment);
        log.info("保存用户互相评论完成，count={}", count);

        CommentDto commentDto = new CommentDto();
        // 属性值复制
        BeanUtils.copyProperties(comment, commentDto);
        // 设置评论id、区块id、用户id、用户名称和用户头像属性值
        commentDto.setCommentId(comment.getCommentId().toString())
                .setBlockId(blogCommentVo.getBlockId().toString())
                .setUserId(user.getUserId().toString())
                .setUserName(user.getUsername())
                .setUserAvatar(user.getAvatar());
        return commentDto;
    }

    @Override
    public PageDto<CommentDto> getCommentList(CommentFormVo commentFormVo) {

        // 构造mp分页对象
        Page<CommentDto> page = PageQuery.initPage(commentFormVo);
        // 查询数据库系统博客评论表，分页查询博客评论信息
        baseMapper.getCommentList(page, commentFormVo);

        for (CommentDto blogComment : page.getRecords()) {
            if (!blogComment.getOneCommentFlag().equals(CommonEnum.ZERO.getStringValue())) {
                // 不是一级评论，则该值统一设置为1
                blogComment.setOneCommentFlag("1");
            }
        }

        // 结果封装
        return new PageDto<>(page);
    }

    @Override
    public PageDto<CommentDto> getOneCommentList(BlogCommentVo blogCommentVo) {
        Long blogId = blogCommentVo.getBlogId();

        List<CommentDto> commentDtoList = new ArrayList<>();
        if (blogCommentVo.getPage() == 1) {
            /*
                如果查询的是第一页，则将所有置顶评论一块查出来
             */
            // 根据博客id，获取该博客的置顶评论列表
            List<CommentDto> topCommentList = this.getTopCommentList(blogId, blogCommentVo.getUserId());
            commentDtoList.addAll(topCommentList);
        }
        // 构造mp分页对象
        Page<CommentDto> page = PageQuery.initPage(blogCommentVo);
        // 分页查询博客第一级评论信息
        baseMapper.getOneCommentList(page, blogId, blogCommentVo.getUserId(), CommonEnum.ZERO.getLongValue(),
                CommentEnum.TOP_NO.getValue(), CommonEnum.ZERO.getValue(), CommonEnum.ZERO.getValue());
        List<CommentDto> oneCommentList = page.getRecords();
        // 合并 置顶评论 和 正常评论
        commentDtoList.addAll(oneCommentList);

        for (CommentDto commentDto : commentDtoList) {
            // 评论id、区块id和用户id
            commentDto.setCommentId(commentDto.getCommentId())
                    .setBlockId(commentDto.getBlockId())
                    .setUserId(commentDto.getUserId());
            if (StringUtils.isNotBlank(commentDto.getLikeFlag())) {
                // 如果用户点赞博客标记属性值不为空，则说明点赞过该博客
                commentDto.setLikeFlag("1");
            }
        }

        // 返回结果封装
        return new PageDto<>(commentDtoList, page.getTotal(), blogCommentVo.getPage(), blogCommentVo.getLimit());
    }

    @Override
    public List<CommentDto> getChildrenCommentList(BlogCommentVo blogCommentVo) {
        // 构造mp分页对象
        Page<CommentDto> page = PageQuery.initPage(blogCommentVo);
        // 分页查询第一级评论的子评论信息
        baseMapper.getChildCommentList(page, blogCommentVo.getBlogId(), blogCommentVo.getBlockId(),
                blogCommentVo.getUserId(), CommonEnum.ZERO.getLongValue(), CommonEnum.ZERO.getValue(),
                CommonEnum.ZERO.getValue());
        List<CommentDto> commentDtoList = page.getRecords();

        for (CommentDto commentDto : commentDtoList) {
            // 评论id、区块id和用户id
            commentDto.setCommentId(commentDto.getCommentId())
                    .setBlockId(commentDto.getBlockId())
                    .setUserId(commentDto.getUserId());
            if (StringUtils.isNotBlank(commentDto.getLikeFlag())) {
                // 如果用户点赞博客标记属性值不为空，则说明点赞过该博客
                commentDto.setLikeFlag("1");
            }
        }

        return commentDtoList;
    }

    @Override
    public BlogCommentEntity getCommentInfo(Long commentId) {

        LambdaQueryWrapper<BlogCommentEntity> blogCommentLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 评论主键 字段
        blogCommentLambdaWrapper.eq(BlogCommentEntity::getCommentId, commentId)
                .eq(BlogCommentEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询数据库系统博客评论表，获取博客评论信息
        List<BlogCommentEntity> blogCommentList = this.list(blogCommentLambdaWrapper);
        if (blogCommentList.isEmpty()) {
            log.info("博客评论列表为空。commentId={}", commentId);
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "博客评论信息不存在，请确认，如有问题，请联系管理员处理。");
        }
        return blogCommentList.get(0);
    }

    @Override
    public void existBlogComment(Collection<Long> commentIdCollection) {
        if (Objects.isNull(commentIdCollection)) {
            log.info("传入博客评论主键为空");
            return;
        }
        LambdaQueryWrapper<BlogCommentEntity> blogCommentLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 评论主键 字段
        blogCommentLambdaWrapper.in(BlogCommentEntity::getCommentId, commentIdCollection);
        // 查询数据库系统博客评论表，统计博客评论主键出现的次数
        long count = this.count(blogCommentLambdaWrapper);
        log.info("判断博客评论是否存在完成。count={}", count);
        if (count == 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您回复的评论不存在，请确认，如有问题，请联系管理员处理。");
        }
    }

    @Override
    public Long getBlogCommentCount(Long blogId) {
        LambdaQueryWrapper<BlogCommentEntity> blogCommentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        blogCommentLambdaQueryWrapper.eq(Objects.nonNull(blogId), BlogCommentEntity::getBlogId, blogId)
                .eq(BlogCommentEntity::getDeleteFlag, CommonEnum.ZERO.getValue());
        // 查询
        Long count = baseMapper.selectCount(blogCommentLambdaQueryWrapper);
        log.info("博客关联评论数量：blogId={} count={}", blogId, count);
        return count;
    }

    @Override
    public int updateOneCommentReplyNum(Long blockId, Integer parentUserId, Integer num) {
        return baseMapper.updateOneCommentReplyNum(blockId, parentUserId, num);
    }

    @Override
    public int updateBlogCommentLikeNum(Long commentId, Integer num, Date updateTime, Long updateUserId) {
        return baseMapper.updateBlogCommentLikeNum(commentId, num, updateTime, updateUserId);
    }

    @Override
    public void updateCommentLike(CommentFormVo commentFormVo) {
        // 获取正在点赞/取消点赞博客评论的用户id
        Long optUserId = SecurityUtils.getUserId();

        long commentId = commentFormVo.getCommentId();

        BlogCommentEntity blogComment;
        Date date = new Date();
        if (commentFormVo.getType().equals(CommonEnum.ZERO.getValue())) {
            /*
                点赞
             */
            blogComment = new BlogCommentEntity();
            blogComment.setAuthorLike(CommonEnum.ZERO.getValue());
        } else if (commentFormVo.getType().equals(CommonEnum.ONE.getValue())) {
            /*
                取消点赞
             */
            blogComment = new BlogCommentEntity();
            blogComment.setAuthorLike(CommonEnum.ONE.getValue());
        } else {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "操作类型不存在，请确认，如有问题，请联系管理员处理。");
        }

        blogComment.setCommentId(commentId)
                .setUpdateTime(date)
                .setUpdateUserId(optUserId);
        // 操作数据库系统博客评论表，更新博客评论信息
        int count = baseMapper.updateById(blogComment);
        log.info("修改博客评论完成。count={}", count);
        if (count == 0) {
            throw new CzzException("修改博客评论‘作者是否点赞’状态失败，请务必及时处理");
        }
    }

    @Override
    public void updateCommentTopFlag(CommentFormVo commentFormVo) {
        // 获取正在置顶/取消置顶博客评论的用户id
        Long optUserId = SecurityUtils.getUserId();

        long commentId = commentFormVo.getCommentId();

        /*
            判断博客评论是否存在
         */
        this.existBlogComment(Collections.singletonList(commentId));

        BlogCommentEntity blogComment = new BlogCommentEntity();
        // 设置评论主键、评论置顶状态、更新时间和操作更新的用户id属性值
        blogComment.setCommentId(commentId)
                .setTopFlag(commentFormVo.getTopFlag())
                .setUpdateTime(new Date())
                .setUpdateUserId(optUserId);
        // 操作数据库系统博客评论表，更新博客评论置顶状态
        int count = baseMapper.updateById(blogComment);
        log.info("修改博客评论置顶状态完成。count={}", count);
    }

    @Override
    public void updateCommentHideFlag(CommentFormVo commentFormVo) {
        // 获取正在隐藏/取消隐藏博客评论的用户id
        Long optUserId = SecurityUtils.getUserId();

        long commentId = commentFormVo.getCommentId();

        /*
            判断博客评论是否存在
         */
        this.existBlogComment(Collections.singletonList(commentId));

        BlogCommentEntity blogComment = new BlogCommentEntity();
        // 设置评论主键、评论隐藏状态、更新时间和操作更新的用户id属性值
        blogComment.setCommentId(commentId)
                .setHideFlag(commentFormVo.getHideFlag())
                .setUpdateTime(new Date())
                .setUpdateUserId(optUserId);
        // 操作数据库系统博客评论表，更新博客评论隐藏状态
        int count = baseMapper.updateById(blogComment);
        log.info("修改博客评论隐藏状态完成。count={}", count);
    }

    @Override
    public void batchUpdateCommentHideFlag(List<Long> commentIdList, Integer hideFlag) {
        // 获取正在批量隐藏/取消隐藏博客评论的用户id
        Long optUserId = SecurityUtils.getUserId();

        /*
            判断博客评论是否存在
         */
        this.existBlogComment(commentIdList);

        LambdaUpdateWrapper<BlogCommentEntity> blogCommentLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置 评论隐藏状态、更新时间和操作更新的用户id 字段值
        blogCommentLambdaUpdateWrapper.set(BlogCommentEntity::getHideFlag, hideFlag)
                .set(BlogCommentEntity::getUpdateTime, new Date())
                .set(BlogCommentEntity::getUpdateUserId, optUserId);
        // 匹配 评论主键（’批量‘） 字段
        blogCommentLambdaUpdateWrapper.in(BlogCommentEntity::getCommentId, commentIdList);
        // 操作数据库系统博客评论表，批量更新博客评论隐藏状态
        int count = baseMapper.update(null, blogCommentLambdaUpdateWrapper);
        log.info("更新博客评论隐藏状态完成。count={}", count);
    }

    /**
     * 根据博客id，获取该博客的置顶评论列表
     * @param blogId 博客id
     * @return 被置顶评论列表
     */
    private List<CommentDto> getTopCommentList(Long blogId, Long userId) {
        log.info("获取博客所有被置顶的评论：{}", blogId);

        Page<CommentDto> page = new Page<>(1, CommentEnum.TOP_COMMENT_SIZE.getValue());
        // 获取博客可用置顶评论信息
        baseMapper.getOneCommentList(page, blogId, userId, CommonEnum.ZERO.getLongValue(),
                CommentEnum.TOP_YES.getValue(), CommonEnum.ZERO.getValue(), CommonEnum.ZERO.getValue());

        log.info("返回所有被置顶的评论");
        return page.getRecords();
    }

    /**
     * 初始化博客评论的基本信息
     * @param comment 封装博客评论或互相评论信息的对象
     */
    private void initCommentField(BlogCommentEntity comment, UserPo user) {
        Date date = new Date();
        // 设置评论用户id、是否删除（正常）、是否隐藏（正常）、作者点赞（正常）、是否置顶（正常）、点赞数、评论被回复量、
        //  更新时间、操作更新的用户id、创建时间和操作创建的用户id属性值
        comment.setUserId(user.getUserId())
                .setDeleteFlag(CommonEnum.ZERO.getValue())
                .setHideFlag(CommentEnum.HIDE_NO.getValue())
                .setAuthorLike(CommentEnum.AUTHOR_DISLIKE.getValue())
                .setTopFlag(CommentEnum.TOP_NO.getValue())
                .setLikeNum(CommentEnum.LIKE_NUM.getValue())
                .setReplyNum(CommentEnum.REPLY_NUM.getValue())
                .setUpdateTime(date)
                .setUpdateUserId(user.getUserId())
                .setCreateTime(date)
                .setCreateUserId(user.getUserId());
    }

}